﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SQLite;
using System.IO;
using System.Diagnostics;

namespace BackgrounderService
{
    class DataBaseWrap
    {

        public DataBaseWrap()
        {

            DbName = Properties.Settings.Default.DbName;
            CacheSize = Properties.Settings.Default.CacheSize;
            InitialConnection();                //初始化数据库连接
            InitialCommand();                   //初始化基本命令
            InitialCacheScheme();               //初始化缓冲结构
            HookWrap.OnClick += this.OnMouseClick;
            HookWrap.OnKeyPress += this.OnKeyPress;
            HookWrap.OnSysInfo += this.OnSysInfoRecieve;
        }
        
        ~DataBaseWrap()
        {
            FlushMouseCache();
            FlushKeyCache();
        }

        public ConnectionState DbState
        {
            get
            {
                return connection.State;
            }
        }

        public int CacheSize
        {
            set
            {
                cacheSize = value;
            }
            get
            {
                return cacheSize;
            }
        }

        #region Initialization
        private void CreateDataBase()           //创建数据库
        {
            SQLiteConnection.CreateFile(DbName);
            connection.Open();
            IDbCommand CreateMouseTableCmd = new SQLiteCommand("CREATE TABLE MouseRecords(xpos SMALLINT,ypos SMALLINT,process NVARCHAR(20),timestamp DATETIME)", connection);
            IDbCommand CreateKeyBoardTableCmd = new SQLiteCommand("CREATE TABLE KeyRecords(key SMALLINT,process NVARCHAR(20),timestamp DATETIME)", connection);
            IDbCommand CreateSystemPerformanceTableCmd = new SQLiteCommand("CREATE TABLE SysPerfRecords(cpu SMALLINT,memory SMALLINT,diskwrite INT,diskread INT,timestamp DATETIME)", connection);
            CreateSystemPerformanceTableCmd.ExecuteNonQuery();
            CreateMouseTableCmd.ExecuteNonQuery();
            CreateKeyBoardTableCmd.ExecuteNonQuery();
        }
        private void InitialConnection()
        {
            connection = new SQLiteConnection("Data Source=" + DbName + ";Pooling=true;FailIfMissing=true");

            try
            {
                connection.Open();
            }
            catch (System.Exception ex)
            {
                CreateDataBase();
            }
            finally
            {
                // connection.Open();
            }
        }     //初始化连接信息
        private void InitialCacheScheme()
        {
            MouseCache = new DataTable("MouseCache");
            KeyCache = new DataTable("KeyCache");
            MouseCache.Columns.Add("xpos", typeof(short));
            MouseCache.Columns.Add("ypos", typeof(short));
            MouseCache.Columns.Add("process", typeof(string));
            MouseCache.Columns.Add("timestamp", typeof(string));
            KeyCache.Columns.Add("key", typeof(short));
            KeyCache.Columns.Add("process", typeof(string));
            KeyCache.Columns.Add("timestamp", typeof(string));
        }    //初始化缓存结构
        private void InitialCommand()
        {
            BeginTrans = new SQLiteCommand("BEGIN TRANSACTION", connection);
            CommitTras = new SQLiteCommand("COMMIT TRANSACTION", connection);

            MouseInsertCommand = new SQLiteCommand("INSERT INTO MouseRecords VALUES" +
                "( @xpos, @ypos , @process , @timestamp )", connection);
            MouseInsertCommand.Parameters.Add(new SQLiteParameter("@xpos", DbType.Int16, "xpos"));
            MouseInsertCommand.Parameters.Add(new SQLiteParameter("@ypos", DbType.Int16, "ypos"));
            MouseInsertCommand.Parameters.Add(new SQLiteParameter("@process", DbType.String, 20, "process"));
            MouseInsertCommand.Parameters.Add(new SQLiteParameter("@timestamp", DbType.DateTime, "timestamp"));

            KeyInsertCommand = new SQLiteCommand("INSERT INTO KeyRecords VALUES" +
                "(@key,@process,@timestamp)", connection);
            KeyInsertCommand.Parameters.Add(new SQLiteParameter("@key", DbType.Int16, "key"));
            KeyInsertCommand.Parameters.Add(new SQLiteParameter("@process", DbType.String, 20, "process"));
            KeyInsertCommand.Parameters.Add(new SQLiteParameter("@timestamp", DbType.DateTime, "timestamp"));

            SysPerfInsertCommand = new SQLiteCommand("INSERT INTO SysPerfRecords VALUES" +
                "(@cpu,@memory,@diskwrite,@diskread,@timestamp)", connection);
            SysPerfInsertCommand.Parameters.Add(new SQLiteParameter("@cpu", DbType.Int16, "cpu"));
            SysPerfInsertCommand.Parameters.Add(new SQLiteParameter("@memory", DbType.Int16, "memory"));
            SysPerfInsertCommand.Parameters.Add(new SQLiteParameter("@diskwrite", DbType.Int32, "memory"));
            SysPerfInsertCommand.Parameters.Add(new SQLiteParameter("@diskread", DbType.Int32, "memory"));
            SysPerfInsertCommand.Parameters.Add(new SQLiteParameter("@timestamp", DbType.DateTime, "timestamp"));
        }        //初始化命令
        #endregion


        #region 与HOOK交互的回调函数

        private void OnMouseClick(MouseEventArgs e)
        {
            lock (DataBaseWrap.MouseCacheLock)
            {
                var row = MouseCache.NewRow();
                row[0] = e.MouseXPos;
                row[1] = e.MouseYPos;
                row[2] = e.ProcessName;
                row[3] = e.Time;
                MouseCache.Rows.Add(row);
                // Console.WriteLine(e.MouseXPos.ToString() + " " + e.MouseYPos.ToString());
                if (MouseCache.Rows.Count > CacheSize)
                    this.FlushMouseCache();
            }
        }

        private void OnKeyPress(KeyEventArgs e)
        {
            lock (DataBaseWrap.KeyCacheLock)
            {
                var row = KeyCache.NewRow();
                row[0] = e.VKey;
                row[1] = e.ProcessName;
                row[2] = e.Time;
                KeyCache.Rows.Add(row);
                //Console.WriteLine(e.VKey.ToString() + " " + e.ProcessName.ToString());
                if (KeyCache.Rows.Count > CacheSize)
                    this.FlushKeyCache();
            }
        }

        private void OnSysInfoRecieve(SysPerfArgs e)
        {
            lock (SysInsertLock)
            {
                SysPerfInsertCommand.Parameters["@cpu"].Value = e.cpu;
                SysPerfInsertCommand.Parameters["@memory"].Value = e.memory;
                SysPerfInsertCommand.Parameters["@diskwrite"].Value = e.diskwrite;
                SysPerfInsertCommand.Parameters["@diskread"].Value = e.diskread;
                SysPerfInsertCommand.Parameters["@timestamp"].Value = e.Time;
                SysPerfInsertCommand.ExecuteNonQuery();
            }
        }

        public void FlushMouseCache()
        {
            lock (MouseCacheLock)
            {
                Adapter.InsertCommand = MouseInsertCommand;
                try
                {
                    BeginTrans.ExecuteNonQuery();
                    Adapter.Update(MouseCache);
                    CommitTras.ExecuteNonQuery();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                    CommitTras.ExecuteNonQuery();
                }
                MouseCache.Clear();
                MouseCache.AcceptChanges();
                //MouseCache.Reset();
                //Console.WriteLine("FLUSH OVER");

            }
            //GC.Collect();
        }       //同步缓冲到数据库

        public void FlushKeyCache()
        {
            lock (MouseCacheLock)
            {
                Adapter.InsertCommand = KeyInsertCommand;
                try
                {
                    BeginTrans.ExecuteNonQuery();
                    Adapter.Update(KeyCache);
                    CommitTras.ExecuteNonQuery();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                    CommitTras.ExecuteNonQuery();
                }
                KeyCache.Clear();
                KeyCache.AcceptChanges();

            }

        }

        #endregion


        #region  Fields
        private int cacheSize;
        private string DbName;                      //数据库名
        private SQLiteConnection connection;                        //数据库连接
        private SQLiteDataAdapter Adapter = new SQLiteDataAdapter();//数据库适配器
        private DataTable MouseCache;                               //鼠标缓冲
        private DataTable KeyCache;                                 //键盘缓冲

        private SQLiteCommand SysPerfInsertCommand;
        private IDbCommand BeginTrans;                              //事务开始
        private IDbCommand CommitTras;                              //事务结束
        private SQLiteCommand MouseInsertCommand;                   //作用于ADAPTER的INSERT
        private SQLiteCommand KeyInsertCommand;

        private static object SysInsertLock = new object();
        private static object MouseCacheLock = new object();         //同步线程锁
        private static object KeyCacheLock = new object();
        #endregion
    }
}
